import socket
import threading
import sys
import framework
import logging

# 在程序入口模块，设置logging日志的配置信息，只配置一次，整个程序都可以使用
logging.basicConfig(level=logging.DEBUG,
                    format="%(asctime)s-%(filename)s[lineno:%(lineno)d]-%(levelname)s-%(message)s",
                    filename="log.txt",
                    filemode='a'
                    )

class HttpWebServer(object):
    def __init__(self,port):
        tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
        tcp_server_socket.bind(('', port))
        tcp_server_socket.listen(128)
        #把tcp服务器的
        self.tcp_server_socket=tcp_server_socket

    def start(self):
        while True:
            new_socket, ip_port = self.tcp_server_socket.accept()
            custom_thr = threading.Thread(target=self.web_thr, args=(new_socket, ip_port), daemon=True)
            print(custom_thr)
            custom_thr.start()

    @staticmethod
    def web_thr(new_socket, ip_port):
            recv_data = new_socket.recv(4096)
            if len(recv_data) == 0:
                new_socket.close()
                return
            # 对二进制进行解码
            recv_content = recv_data.decode('utf-8')
            request_list = recv_content.split(" ", 2)
            request_path = request_list[1]
            print(request_path)
            # 判断请求是否是根目录，是根，就返回index.html
            if request_path == "/":
                request_path = '/index.html'

            # 判断是否是动态资源请求，以后把后缀.html是动态请求的处理
            if request_path.endswith(".html"):
                '''动态资源请求'''
                logging.info('动态资源请求的地址：'+request_path)
                # 动态资源请求，需要把请求参数给web框架
                # 准备给web框架的参数信息
                env = {
                    "request_path":request_path,
                    #额外参数，可以在字典里面进行添加
                }
                # 使用框架处理动态资源请求，web框架需要把处理结果返回给web服务器
                status,headers,response_body=framework.handle_request(env)
                print(status,headers,response_body)
                # 响应行
                response_line="http/1.1 %s\r\n" % status
                # 响应头
                response_header = ""
                for header in headers:
                    response_header += "%s: %s\r\n" % header
                response_data = (response_line + response_header + "\r\n" + response_body).encode("utf-8")
                #发送响应报文给浏览器
                new_socket.send(response_data)
                new_socket.close()
            else:
                '''静态资源请求'''
                logging.info('静态资源请求的地址：' + request_path)
                # 为了兼容图片，需要用二进制方式打开“rb”
                #1.判断文件是否存在 os.path.exists("static"+request_path)
                #2.try去捕获
                try:
                    with open(f'./static{request_path}', 'rb') as file:
                        file_data = file.read()
                except Exception as e:
                    # 响应行----
                    response_line = "HTTP/1.1 404 Not Found\r\n"
                    # 响应头
                    response_head = "Server:Pws/1.0\r\n"
                    with open('static/error.html','rb') as file:
                        file_data=file.read()
                    response_body = file_data
                    #因为响应体已经的是二进制，所以只需要把请求行和请求头，一起转码成二进制就行了
                    response = (response_line +
                                response_head +
                                "\r\n").encode('utf-8') + response_body
                    new_socket.send(response)

                else:
                    # 封装
                    # 响应行----
                    response_line = "HTTP/1.1 200 OK\r\n"
                    # 响应头
                    response_head = "Server:Pws/1.0\r\n"
                    # 响应体
                    response_body = file_data
                    #因为响应体已经的是二进制，所以只需要把请求行和请求头，一起转码成二进制就行了
                    response = (response_line +
                                response_head +
                                "\r\n").encode('utf-8') + response_body
                    new_socket.send(response)
                finally:
                    new_socket.close()

def main():
    if len(sys.argv)!=2:
        print('你输入的参数有误，准确的方式是：XXX.py port')
        logging.warning('在终端启动程序参数的个数不等于2')
        return
    if not sys.argv[1].isdigit():
        print('你输入的端口不是数字，准确的方式是：XXX.py port')
        logging.warning('在终端启动程序参数的类型不是数字')
        return
    port=int(sys.argv[1])
    web_server = HttpWebServer(port)
    web_server.start()

if __name__ == '__main__':
    main()